package com.yanyeori.framework.security.service;

import com.yanyeori.framework.core.constant.BaseWebCodeEnum;
import com.yanyeori.framework.core.model.WebResponse;
import com.yanyeori.framework.security.bo.InterPermsBO;
import com.yanyeori.framework.security.bo.UserDetail;
import com.yanyeori.framework.security.cache.PermissionsCache;
import com.yanyeori.framework.security.configprop.SecurityConfigProps;
import com.yanyeori.framework.security.database.InterfaceDao;
import com.yanyeori.framework.security.util.SecurityUtil;
import org.apache.commons.collections4.CollectionUtils;

import javax.annotation.PostConstruct;
import java.lang.ref.SoftReference;
import java.util.*;

/**
 * 用户接口鉴权服务
 *
 * @author chenkuan 2020/12/11
 */
public class DefaultPermissionsService implements PermissionsService {

    private final SecurityConfigProps config;
    private final InterfaceDao interfaceDao;

    public DefaultPermissionsService(SecurityConfigProps config, InterfaceDao interfaceDao) {
        this.config = config;
        this.interfaceDao = interfaceDao;
    }

    /**
     * 校验用户是否具有访问接口的权限
     *
     * @param userDetail  用户信息
     * @param servletPath 接口url
     */
    @Override
    public WebResponse<?> validUserInterfacePer(UserDetail userDetail, String servletPath) {
        if (!config.isEnableInterfacePerAuth()) {
            return WebResponse.ok();
        }
        if (!config.isDevMode()) {
            Map<String, Set<String>> softVerMap = PermissionsCache.VER_PERMISSIONS.get();
            if (softVerMap != null && softVerMap.getOrDefault(userDetail.getUserId(), new HashSet<>()).contains(servletPath)) {
                return WebResponse.ok();
            }
        }
        Set<String> interfaces = getInterfacePermissions(userDetail.getUserId());
        if (CollectionUtils.isNotEmpty(interfaces)) {
            for (String inter : interfaces) {
                if (SecurityUtil.matchPath(inter, servletPath)) {
                    if (!config.isDevMode()) {
                        Map<String, Set<String>> softVerMap = PermissionsCache.VER_PERMISSIONS.get();
                        if (softVerMap == null) {
                            softVerMap = new HashMap<>();
                            PermissionsCache.VER_PERMISSIONS = new SoftReference<>(softVerMap);
                        }
                        softVerMap.computeIfAbsent(userDetail.getUserId(), k -> new HashSet<>()).add(servletPath);
                    }
                    return WebResponse.ok();
                }
            }
        }
        return WebResponse.fail(BaseWebCodeEnum.NO_RESOURCE_PERMISSIONS.code(), BaseWebCodeEnum.NO_RESOURCE_PERMISSIONS.msg(), servletPath);
    }

    /**
     * 根据用户加载相关接口
     * return Map<String, Set<String>> Map<UserId, Set<interface_url>>
     */
    @Override
    public Map<String, Set<String>> loadInterfacePermissionsByUser(String userId) {
        List<InterPermsBO> interPermsBOList = interfaceDao.listUserInterPermsByUser(userId);
        return initInterPermsMap(interPermsBOList);
    }

    private Map<String, Set<String>> initInterPermsMap(List<InterPermsBO> interPermsBOList) {
        Map<String, Set<String>> interPermsMap = new HashMap<>();
        for (InterPermsBO perms : interPermsBOList) {
            interPermsMap.computeIfAbsent(perms.getUserId(), k -> new HashSet<>()).add(perms.getBackUrl());
        }
        return interPermsMap;
    }

    private Set<String> getInterfacePermissions(String userId) {
        if (config.isDevMode()) {
            return loadInterfacePermissionsByUser(userId).get(userId);
        } else {
            return PermissionsCache.PERMISSIONS_MAP.get(userId);
        }
    }

    /**
     * 系统启动时加载所有匿名接口
     */
    @PostConstruct
    public void loadAnnoInterfaces() {
        if (!config.isDevMode()) {
            PermissionsCache.ANNO_INTERFACE_LIST.addAll(listAnnoInterfaces());
        }
    }

    /**
     * 刷新所有匿名接口
     */
    @Override
    public void flushAnnoInterfaces() {
        PermissionsCache.ANNO_INTERFACE_LIST.clear();
        PermissionsCache.ANNO_INTERFACE_LIST.addAll(listAnnoInterfaces());
    }

    /**
     * 查询所有匿名接口
     */
    @Override
    public List<String> listAnnoInterfaces() {
        return interfaceDao.listAnnoInterfaces();
    }
}
